
module xpip_rtl_isu(
  input logic clk, rst_n,
  xpip_intf.isu inf
);
  `XPIP_DEF_PARAM
  parameter int sliceId = 0;
  
  isu_thrd_inf_s ti[NUM_LANE][NUM_THRD], tin[NUM_LANE][NUM_THRD];
  
  isu_lane_inf_s li[NUM_LANE], lin[NUM_LANE];
  
  isu_rf_inf_s rfi[MCV][NUM_LANE], rfin[MCV][NUM_LANE],
               rfi2[MCV][NUM_LANE], rfi2n[MCV][NUM_LANE];
  
  isu_fui3_inf_s fui[NUM_FU], fuin[NUM_FU],
                 fui2[NUM_FU], fui2n[NUM_FU];
  isu_lsi2_inf_s lsi, lsin, lsi2, lsi2n;
  isu_spi_inf_s spi, spin;
  
  isu_inf_s s, sn;
  isu_io_inf_s io, ion;
  isu_pip_inf_s p[3], pn[3];
  isu_spip_inf_s ps[SG_RRF_SWB:0], psn[SG_RRF_SWB:0];
  
  logic cycStart, cycEnd; ///for issue stage 2
  cyc_t cyc, cycn;
  
  always_ff@(posedge clk or negedge rst_n)
    if(!rst_n) begin
      ti <= '{default: isu_thrd_inf_def};
      li <= '{default: isu_lane_inf_def};
      rfi <= '{default: isu_rf_inf_def};
      spi <= isu_spi_inf_def;
      lsi <= isu_lsi2_inf_def;
      fui <= '{default: isu_fui3_inf_def};
      rfi2 <= '{default: isu_rf_inf_def};
      lsi2 <= isu_lsi2_inf_def;
      fui2 <= '{default: isu_fui3_inf_def};
      s <= isu_inf_def;
      io <= isu_io_inf_def;
      p <= '{default : isu_pip_inf_def};
      ps <= '{default : isu_spip_inf_def};
      cyc <= sliceId;
    end
    else begin
      ti <= tin;
      li <= lin;
      rfi <= rfin;
      spi <= spin;
      lsi <= lsin;
      fui <= fuin;
      s <= sn;
      io <= ion;
      p <= pn;
      ps <= psn;
      
      fui2 <= fui2n;
      lsi2 <= lsi2n;
      rfi2 <= rfi2n;
      cyc <= cycn;
    end
  
  always_comb
  begin : comb_logic
    lid_t ls[2];

    inf.isu2rfu = isu2rfu_def;
    inf.isu2ifu = isu2ifu_def;
    inf.isu2dpu = isu2dpu_def;
    inf.isu2exu = isu2exu_def;
    inf.isu2lsu = isu2lsu_def;
    inf.isu2sau = isu2sau_def;
    
    tin = ti;
    lin = li;
    spin = spi;
    lsin = lsi;
    fuin = fui;
    rfin = rfi;
    pn = p;
    psn = ps;
    sn = s;
    fui2n = fui2;
    lsi2n = lsi2;
    rfi2n = rfi2;
    
    cycn    = cyc + 'b01;
    cycStart  = cyc == '0;
    cycEnd    = cycn == '0;
    sn.l = s.l + 'b01;
        
    spin.wrf.wr = '0;
    spin.en = '0;
    
    ///pip assemble & pass
    for(int i = 1; i <= SG_RRF_SWB; i++)
      if(ps[i-1].en)
        psn[i] = ps[i-1];
      else begin
        psn[i].en = '0;
        psn[i].wrf.wr = '0;
      end
    psn[0].wrf.wr = '0;
    psn[0].en = '0;
    
    if(spi.en) begin
      psn[0].en = '1;
      psn[0].ltid = spi.ltid;
      psn[0].lid = spi.lid;
      psn[0].wrf = spi.wrf;
      psn[0].opcode = spi.opcode;
      psn[0].imm = spi.imm;
    end
    
    if(cycEnd)
      for(int i = 1; i < 3; i++)
        for(int f = 0; f < NUM_FU; f++)
          if(p[i-1].wrf[f].wr) begin
            pn[i].wrf[f] = p[i-1].wrf[f];
            pn[i].ltid[f] = p[i-1].ltid[f];
            pn[i].lid[f] = p[i-1].lid[f];
          end else
            pn[i].wrf[f].wr = '0;
            
    ///update thread info
    for(int l = 0; l < NUM_LANE; l++) 
      for(int t = 0; t < NUM_THRD; t++) begin
        if(ti[l][t].vwcnt != '0 && cycEnd)
           tin[l][t].vwcnt--;
        if(ti[l][t].swcnt != '0 && ti[l][t].vwcnt == '0)
           tin[l][t].swcnt--;
                    
         if(ti[l][t].ts == ts_w_pip && tin[l][t].swcnt == '0 && tin[l][t].vwcnt == '0)
           tin[l][t].ts = ts_rdy;
         
         if(ti[l][t].ts == ts_br_cl)
          tin[l][t].ts = ts_w_if;
      end
    
    ///new fetched inst pre decode, search for max wcnt
    for(int l = 0; l < NUM_LANE; l++) begin
      isu_thrd_inf_s tif;
      isu_rf_adr_s rrf[3];
      isu_wcnt_t vwcnt;
      logic[3:0] swcnt;
      ltid_t ltid;
      
      if(!io.ifu.rsp[l]) continue;
      
      vwcnt = '0;
      swcnt = '0;
      ltid = io.ifu.ltid[l];
      tif = tin[l][ltid];
      isuPreDecode(io.ifu.inst[l], tif);
      rrf = tif.rrf;
      tif.pc = io.ifu.pc[l];
      
      for(int s = 0; s < SG_RRF_SWB; s++)
        for(int r = 0; r < 3; r++) begin
          if(rrf[r].ops inside {opsr, opsm, opsf} && ps[s].wrf.wr && !rrf[r].vec
          && ps[s].ltid == ltid && ps[s].lid == l && ps[s].wrf.adr == rrf[r].adr) begin
            swcnt = SG_RRF_SWB - s;
            break;
           end
        end

      for(int s = 0; s < 3; s++)
        for(int f = 0; f < NUM_FU; f++)
          for(int r = 0; r < 3; r++) begin
            if(rrf[r].ops == opsr && p[s].wrf[f].wr && p[s].wrf[f].adr == rrf[r].adr
            && p[s].ltid[f] == ltid && p[s].lid[f] == l && rrf[r].vec == p[s].wrf[f].vec) begin
              vwcnt = 3 - s;
              break;
             end
          end
      
      if(swcnt > (MCV - 1 - cyc)) begin
        tif.swcnt = swcnt - (MCV - 1 - cyc);
        tif.vwcnt = (swcnt - tif.swcnt) >> WID_VEC;
      end else begin
        tif.swcnt = swcnt;
        tif.vwcnt = '0;
      end
      
      if(vwcnt > tif.vwcnt) begin
        tif.vwcnt = vwcnt;
        tif.swcnt = '0;
      end
       
       if(tif.ts == ts_w_if)
         tif.ts = ts_rdy;
       if(tif.ts == ts_lsex_w_if)
         tif.ts = ts_w_lsex;
       if(tif.ts == ts_br_w_if)
         tif.ts = ts_w_br;
///       if(tif.ts == ts_ba_w_if)
///         tif.ts = ts_w_ba;
                         
       if(tif.ts inside {ts_rdy, ts_w_lsex})///ts_w_ba
        tin[l][ltid] = tif;
    end
    
    ///issue stage 2
    begin
      lid_t l;
      
      l = '0;
      if(li[1].en && !li[1].vec)
        l = 'b01;
      if(li[l].en && !li[l].vec) begin
        spin.en = '1;
        spin.ltid = li[l].ltid;
        spin.lid = l;
        spin.wrf = li[l].wrf;
        spin.rrf = li[l].rrf;
        spin.opcode = li[l].opcode;
        spin.imm = li[l].imm;
        spin.pc = li[l].pc;
        spin.gid = li[l].gid;
      end
      
      l = '0;
      if(li[1].en && li[1].vec)
        l = 'b01;
      ///fill the register bank info for write
      if(li[l].en) begin
        ///fill the register bank info for read
        logic [2:0] rr;
        isu_brf_radr_s rrf[3];
        
        rr = '1;
        rrf = '{default : isu_brf_radr_def};
        for(int r = 0; r < 3; r++) begin
          rrf[r].vec = li[l].rrf[r].vec;
          rrf[r].ops = li[l].rrf[r].ops;
          if(rrf[r].vec)
            rrf[r].bks = li[l].rrf[r].adr;
          else begin
            srfbk_t bks;
            bks = li[l].rrf[r].adr;
            rrf[r].bks = bks;
          end
        end
        
        for(int c = 0; c < MCV; c++) begin
          logic flag;
          flag = '1;
          ///at last cyc, slot 0 can not be modified
          if(cycEnd && c == 0)
            continue;
          for(int r = 0; r < 3; r++) begin
            if(rrf[r].ops == opsr && rr[r]) begin
              if(rrf[r].vec) begin
                if(!rfin[c][l].ven[rrf[r].bks]) begin
                  rfin[c][l].ven[rrf[r].bks] = '1;
                  rfin[c][l].vadr[rrf[r].bks] = {li[l].ltid, li[l].rrf[r].adr[4:WID_VRF_BKS]};
                  rrf[r].cyc = c;
                  rr[r] = '0;
                  flag = '0;
                  break;
                end
              end else begin
                if(!rfin[c][l].sen[rrf[r].bks]) begin
                  rfin[c][l].sen[rrf[r].bks] = '1;
                  rfin[c][l].sadr[rrf[r].bks] = {li[l].ltid, li[l].rrf[r].adr[4:WID_SRF_BKS]};
                  rrf[r].cyc = c;
                  rr[r] = '0;
                  flag = '0;
                  break;
                end
              end
            end
          end
          
          for(int r = 0; r < 3; r++)
            if(flag && rrf[r].ops != opsr && rr[r]) begin
              rrf[r].cyc = c;
              rr[r] = '0;
              break;
            end
        end
        
        ///fill the function unit info
        for(int l = 0; l < NUM_LANE; l++)
          sn.vext |= li[l].it == it_ext;
        if(li[l].it inside {it_int, it_ext} && !fui[2].en) begin
          fuin[2].en = '1;
          fuin[2].ltid = li[l].ltid;
          fuin[2].lid = l;
          fuin[2].wrf = li[l].wrf;
          fuin[2].rrf = rrf;
          fuin[2].opcode = li[l].opcode;
          fuin[2].imm = li[l].imm;
          if(li[l].it == it_ext) begin
            sn.exFu = 2;
            sn.exoid = li[l].oid;
            sn.exasyn = li[l].asyn;
          end
        end else if(li[l].it inside {it_int, it_flt, it_ext}) begin
          if(!fui[0].en) begin
            fuin[0].en = '1;
            fuin[0].ltid = li[l].ltid;
            fuin[0].lid = l;
            fuin[0].wrf = li[l].wrf;
            fuin[0].rrf = rrf;
            fuin[0].opcode = li[l].opcode;
            fuin[0].imm = li[l].imm;
            if(li[l].it == it_ext) begin
              sn.exFu = 0;
              sn.exoid = li[l].oid;
              sn.exasyn = li[l].asyn;
            end
          end else if(!fui[1].en) begin
            fuin[1].en = '1;
            fuin[1].ltid = li[l].ltid;
            fuin[1].lid = l;
            fuin[1].wrf = li[l].wrf;
            fuin[1].rrf = rrf;
            fuin[1].opcode = li[l].opcode;
            fuin[1].imm = li[l].imm;
            if(li[l].it == it_ext) begin
              sn.exFu = 1;
              sn.exoid = li[l].oid;
              sn.exasyn = li[l].asyn;
            end
          end
        end else if(li[l].it == it_lsu) begin
          lsin.en = '1;
          lsin.ltid = li[l].ltid;
          lsin.lid = l;
          lsin.wrf = li[l].wrf;
          lsin.rrf[0] = rrf[0];
          lsin.rrf[1] = rrf[1];
          lsin.opcode = li[l].opcode;
          lsin.imm = li[l].imm;
          lsin.gid = li[l].gid;
          lsin.oid = li[l].oid;
          lsin.asyn = li[l].asyn;
        end
      end
    end
    
    ///rfi2 is required to be one cyc ahead, so adr don't came from rfi2n
    if(cyc == `E1(2'b10))
      rfi2n[0] = rfin[0];
      
    if(cycEnd) begin
      fui2n = fuin;
      lsi2n = lsin;
      rfi2n = rfin;      
    end
    
    ///stage 3, generate adr wr signal for rfu
    begin
      isu_rf_inf_s rfit[NUM_LANE];
      inf.isu2rfu.last = cycEnd;
      inf.isu2rfu.req = cycStart;
      ///adr should be one cyc ahead
      rfit = rfi2[cycn];
        
      for(int l = 0; l < NUM_LANE; l++) begin
         inf.isu2rfu.vradr[l] = rfit[l].vadr;
         inf.isu2rfu.sadr[l] = rfit[l].sadr;

         if(spin.rrf[2].ops == opsr) begin
           srfbk_t bk;
           bk = spin.rrf[2].adr;
           inf.isu2rfu.sadr[l][bk] = spin.rrf[2].adr >> WID_SRF_BKS;
         end
      end
       
      if(ps[SG_RRF_SWB].wrf.wr) begin
        srfbk_t bk;
        bk = ps[SG_RRF_SWB].wrf.adr;
        inf.isu2rfu.swLid[bk] = ps[SG_RRF_SWB].lid;
        inf.isu2rfu.swr[bk] = '1;
        inf.isu2rfu.swadr[bk] = {ps[SG_RRF_SWB].ltid, ps[SG_RRF_SWB].wrf.adr[4:WID_SRF_BKS]};
      end
       
      inf.isu2rfu.spLid = spi.lid;
      inf.isu2rfu.spLtid = spi.ltid;
      inf.isu2rfu.spImm = spi.imm;
      inf.isu2rfu.spPC = spi.pc;
      inf.isu2rfu.spBks = spin.rrf[2].adr;
       
      for(int r = 0; r < 3; r++)
       inf.isu2rfu.spOps[r] = spi.rrf[r].ops;
      
      inf.isu2rfu.lsImm = lsi2.imm;
      inf.isu2rfu.lsLid = lsi2.lid;
      
      for(int r = 0; r < 2; r++) begin
        inf.isu2rfu.spAdr[r] = spin.rrf[r].adr;
         
        if(cyc == lsi2.rrf[r].cyc) begin
          inf.isu2rfu.lsRrf = lsi2.rrf[r];
          inf.isu2rfu.lsPts = isu_ptsel_t'(r);
        end
      end
       
      for(int i = 0; i < NUM_FU; i++) begin
        isu_rf_adr_s wrf;
        lid_t lid;
        vrfbk_t bk;
        
        inf.isu2rfu.fuImm[i] = fui2[i].imm;
        inf.isu2rfu.fuLid[i] = fui2[i].lid;
        
        for(int r = 0; r < 3; r++)
          if(cyc == fui2[i].rrf[r].cyc) begin
            inf.isu2rfu.fuRrf[i] = fui2[i].rrf[r];
            inf.isu2rfu.fuPts[i] = isu_ptsel_t'(r);
          end
        
        wrf = pn[2].wrf[i];
        lid = pn[2].lid[i];
        bk = wrf.adr;
        
        if(wrf.wr && !inf.isu2rfu.vwr[lid][bk]) begin
          pn[2].wrf[i].wr = '0;
          rfit[lid].ven[bk] = DP_VRF_BK == 0;
          inf.isu2rfu.vwr[lid][bk] = '1;
          inf.isu2rfu.vwadr[lid][bk] = {pn[2].ltid[i], wrf.adr[4:WID_VRF_BKS]};
          inf.isu2rfu.fuWSel[lid][bk] = i;
        end
      end
      
      ///respond to lsu exu write back request
      inf.isu2sau.rsp = !io.sau.req;
      if(io.sau.req) begin
        srfadr_t sa;
        srfbk_t sb;
        {sa, sb} = {io.sau.ltid, io.sau.adr};
        inf.isu2sau.rsp = !sn.srfwv[sb];
        sn.srfwv[sb] = '1;
        if(inf.isu2sau.rsp) begin
          sn.srflid[sb] = io.sau.lid;
          sn.srfadr[sb] = sa;
        end
      end
      
      inf.isu2lsu.rsp = !io.lsu.req;
      if(io.lsu.req) begin
        if(io.lsu.ls) begin
          vrfadr_t va;
          vrfbk_t vb;
          {va, vb} = {io.lsu.ltid, io.lsu.adr};
          inf.isu2lsu.rsp = !sn.vrfwv[io.lsu.lid][vb];
          sn.vrfwv[io.lsu.lid][vb] = '1;
          if(inf.isu2lsu.rsp)
            sn.vrfadr[io.lsu.lid][vb] = va;
        end else
          inf.isu2lsu.rsp = '1;
      end
      inf.isu2rfu.lsuRsp = inf.isu2lsu.rsp;
      
      inf.isu2exu.rsp = !io.exu.req;
      if(io.exu.req) begin
        if(io.exu.ls) begin
          if(io.exu.vs) begin
            vrfadr_t va;
            vrfbk_t vb;
            {va, vb} = {io.exu.ltid, io.exu.adr};
            inf.isu2exu.rsp = !sn.vrfwv[io.exu.lid][vb];
            sn.vrfwv[io.exu.lid][io.exu.ltid] = '1;
            if(inf.isu2exu.rsp)
              sn.vrfadr[io.exu.lid][vb] = va;
          end else begin
            srfadr_t sa;
            srfbk_t sb;
            {sa, sb} = {io.exu.ltid, io.exu.adr};
            inf.isu2exu.rsp = !sn.srfwv[sb];
            sn.srfwv[sb] = '1;
            if(inf.isu2exu.rsp) begin
              sn.srflid[sb] = io.exu.lid;
              sn.srfadr[sb] = sa;
            end
          end
        end else
          inf.isu2exu.rsp = '1;
      end
      inf.isu2rfu.exuRsp = inf.isu2exu.rsp;
      
      ///lsu exu write back
      for(int b = 0; b < NUM_SRF_BKS; b++) begin
        if(inf.isu2rfu.swr[b])
          continue;
        inf.isu2rfu.swr[b] = s.srfwv[b];
        inf.isu2rfu.swadr[b] = s.srfadr[b];
        inf.isu2rfu.swLid[b] = s.srflid[b];  
        sn.srfwv[b] = '0;
      end
      
      for(int i = 0; i < NUM_LANE; i++) begin
        for(int b = 0; b < NUM_VRF_BKS; b++) begin
          if(rfit[i].ven[b] || inf.isu2rfu.vwr[i][b])
            continue;
          inf.isu2rfu.vradr[i][b] = s.vrfadr[i][b];
          inf.isu2rfu.vwr[i][b] = s.vrfwv[i][b];
          sn.vrfwv[i][b] = '0;
        end
      end
    end
    
    if(cycEnd) begin
      cyc_t vCnt[NUM_LANE][NUM_VRF_BKS];
      vCnt = '{default : '0};
      
      for(int c = 0; c < MCV; c++)
        for(int l = 0; l < NUM_LANE; l++) begin
          rfin[c][l].ven = '{default : '0};
          rfin[c][l].sen = '{default : '0};
        end
                  
       for(int f = 0; f < NUM_FU; f++) begin
         pn[0].wrf[f].wr = '0;
         if(fuin[f].wrf.wr) begin
          pn[0].wrf[f] = fuin[f].wrf;
          pn[0].ltid[f] = fuin[f].ltid;
          pn[0].lid[f] = fuin[f].lid;
        end

        if(p[1].wrf[f].wr && p[1].wrf[f].vec) begin
          vrfbk_t bk;
          lid_t lane;
          bk = p[1].wrf[f].adr;
          lane = p[1].lid[f];
          rfin[vCnt[lane][bk]][lane].ven[bk] = '1;
          vCnt[lane][bk]++;
        end
      end
      for(int l = 0; l < NUM_LANE; l++) begin
        lin[l].sFilter = '{default : MCV - 1};
        for(int b = 0; b < NUM_VRF_BKS; b++)
          lin[l].vFilter[b] = MCV - 1 - vCnt[l][b];
      end
    end
      
    ///generate signal from stage 2 for stage 1
    ls[0] = s.l;  ///prefer vec
    ls[1] = ~s.l;  ///prefer scl
 
    lin[0].siFilter = '0;
    lin[0].viFilter = '0;
    lin[0].viPrefer = '0;
    
    lin[1].siFilter = '0;
    lin[1].viFilter = '0;
    lin[1].viPrefer = '0;
    
    lin[ls[0]].siFilter = '1;
    
    for(int l = 0; l < NUM_LANE; l++) begin
      logic fb;
      fb = '0;///cyc != `E1(2'b10);
      for(int b = 0; b < NUM_SRF_BKS; b++)
        fb |= rfi2[cycn][l].sen[b];
      lin[l].s3Forb = fb;
    end
    
    if(sn.vext || io.exu.vblock) begin
      lin[0].viFilter[it_ext] = '1;
      lin[1].viFilter[it_ext] = '1;
    end else begin
      lin[ls[0]].viPrefer[it_ext] = '1;
      lin[ls[1]].viFilter[it_ext] = '1;      
    end
    
    if(io.exu.sblock) begin
      lin[0].siFilter[it_ext] = '1;
      lin[1].siFilter[it_ext] = '1;      
    end
        
    if(lsin.en || io.lsu.vblock) begin
      lin[0].viFilter[it_lsu] = '1;
      lin[1].viFilter[it_lsu] = '1;
    end else begin
      lin[ls[0]].viPrefer[it_lsu] = '1;
      lin[ls[1]].viFilter[it_lsu] = '1;
    end

    if(io.sau.sblock) begin
      lin[0].siFilter[it_lsu] = '1;
      lin[1].siFilter[it_lsu] = '1;      
    end
        
    if(fuin[0].en && fuin[1].en) begin
      lin[0].viFilter[it_flt] = '1;
      lin[1].viFilter[it_flt] = '1;      
    end
    
    if(fuin[0].en || fuin[1].en)
      lin[ls[1]].viFilter[it_lsu] = '1;
      
    ///stage 1 selection
    for(int l = 0; l < NUM_LANE; l++) begin
      logic[NUM_THRD-1:0] v, p;
      logic[NUM_THRD*2-1:0] selVec;
      logic pf;
      ltid_t sel;
      selVec = '0;
      sel = '0;
      pf = '0;
      
      lin[l].en = '0;
      lin[l].viRdy = '0;
      lin[l].siRdy = '0;
      for(int i = 0; i < NUM_THRD; i++) begin
        v[i] = ti[l][i].ts == ts_rdy;
        
        if(ti[l][i].vec) begin
          v[i] = v[i] && !lin[l].viFilter[ti[l][i].it];
          for(int j = 0; j < NUM_VRF_BKS; j++)
            v[i] = v[i] && ti[l][i].vbkCnt[j] <= li[l].vFilter[j];
          for(int j = 0; j < NUM_SRF_BKS; j++)
            v[i] = v[i] && ti[l][i].sbkCnt[j] <= li[l].sFilter[j];
          p[i] = v[i] && lin[l].viPrefer[ti[l][i].it];          
          if(cycEnd)
            lin[l].viRdy[ti[l][i].it] |= v[i];
          else
            lin[l].viRdy[ti[l][i].it] |= p[i];
        end else begin
          lin[l].siRdy |= v[i];
          v[i] = v[i] && !lin[l].siFilter[ti[l][i].it];
          v[i] = v[i] && !(lin[l].s3Forb && ti[l][i].rrf[2].ops == opsr);
          p[i] = v[i] && (!lin[l].s3Forb && ti[l][i].rrf[2].ops == opsr);
        end
      end
      
      selVec = {v, v};
      for(int j = 0; j < NUM_THRD*2; j++)
        if(j > li[l].pfTid && selVec[j] && (!pf || p[sel])) begin
          sel = j;
          pf = p[sel];
        end
      
      lin[l].en = v[sel];
      
      if(cycEnd) begin
        ltid_t nSel;
        nSel = '0;
        for(int i = 0; i < NUM_THRD; i++)
          v[i] = ti[l][i].ts == ts_rdy;
        selVec = {v, v};
        for(int j = 0; j < NUM_THRD*2; j++)
          if(j > li[l].pfTid && selVec[j]) begin
            nSel = j;
            break;
          end
        lin[l].pfTid = nSel;
      end else if(lin[l].en) begin
        for(int j = 0; j < NUM_VRF_BKS; j++)
          lin[l].vFilter[j] = li[l].vFilter[j] - ti[l][sel].vbkCnt[j];
        for(int j = 0; j < NUM_SRF_BKS; j++)
          lin[l].sFilter[j] = li[l].sFilter[j] - ti[l][sel].sbkCnt[j];
      end

      if(lin[l].en) begin
        isu_thrd_inf_s tif;
        tif = ti[l][sel];
        lin[l].it = tif.it;
        lin[l].imm = tif.imm;
        lin[l].pc = tif.pc;
        lin[l].rrf = tif.rrf;
        lin[l].wrf = tif.wrf;
        lin[l].vec = tif.vec;
        lin[l].opcode = tif.opcode;
        lin[l].gid = tif.gid;
        lin[l].ltid = sel;
        lin[l].oid = tif.it == it_ext ? tif.oid[2] : tif.oid[tif.opcode[8]];
        lin[l].asyn = tif.asyn;
        
        inf.isu2ifu.req[l] = '1;
        inf.isu2ifu.ltid[l] = sel;
                
        if(tif.it == it_lsu) begin
          if(!tif.asyn)
            tif.ts = ts_lsex_w_if;
          else begin
            logic ls;
            ls = tif.opcode[8];
            tif.ts = ts_w_if;
            tif.ocnt[ls] = {tif.ocnt[ls], 1'b1};
            tif.oid[ls] = {tif.oid[ls], (tif.oid[ls][0] + 1'b1)};
          end
        end else if(tif.it == it_ext) begin
          if(!tif.asyn)
            tif.ts = ts_lsex_w_if;
          else begin
            tif.ts = ts_w_if;
            tif.ocnt[2] = {tif.ocnt[2], 1'b1};
            tif.oid[2] = {tif.oid[2], (tif.oid[2][0] + 1'b1)};
          end
        end else
          tif.ts = ts_w_if;
        
        tin[l][sel] = tif;
      end
    end

    if(cycEnd) begin
      sn.vext = '0;///vec only , scl is handled by dpu
      lsin.en = '0;
      lsin.wrf.wr = '0;
      for(int f = 0; f < NUM_FU; f++) begin
        fuin[f].en = '0;
        fuin[f].wrf.wr = '0;
      end
    end
    
    ///process dpu branch rsp
    if(io.dpu.req) begin
      isu_thrd_inf_s tif;
      lid_t lid;
      ltid_t ltid;
      
      lid = ps[SG_BR_RSP].lid;
      ltid = ps[SG_BR_RSP].ltid;
      tif = tin[lid][ltid];
      
      casez(ps[SG_BR_RSP].opcode)
      9'b01001_????: ///branch
      begin
        inf.isu2ifu.brLid = lid;
        inf.isu2ifu.brLtid = ltid;
        inf.isu2ifu.pc = io.dpu.data;
        if(tif.ts == ts_w_br) begin
          if(tif.pc != io.dpu.data) begin
            inf.isu2ifu.br = '1;
            tif.ts = ts_br_cl;
          end else
            tif.ts = ts_rdy;
        end else begin
          inf.isu2ifu.br = '1;
          tif.ts = ts_br_cl;        
        end
      end
      op_mtsr:
      begin
      end
      op_mfsr:
      begin
        inf.isu2dpu.srRsp = '1;
        inf.isu2dpu.sr = '0;
      end
      9'b0101?_????: ///cop inst
      begin
///        case(ps[SG_BR_RSP].opcode[4:0])
///          5'b001100:
///          begin
///            
///          end
///        endcase
      end
      endcase
      tin[lid][ltid] = tif;
    end
    
    ///process isu lsu finish rsp
    if(io.lsu.req && inf.isu2lsu.rsp) begin
      isu_thrd_inf_s tif;
      tif = tin[io.lsu.lid][io.lsu.ltid];
      if(io.lsu.asyn) begin
        isu_oid_t oid;
        oid = '0;
        for(int i = 0; i < NUM_ISU_OCNT; i++)
          if(tif.oid[io.lsu.ls][i] == io.lsu.oid && tif.ocnt[io.lsu.ls][i])
            oid = i;
        tif.ocnt[oid] = '0;
      end else
        tif.sblock[0] = '0;
      if(!tif.sblock[0] && (tif.ocnt[0] & tif.omsk[0]) == '0
      && (tif.ocnt[1] & tif.omsk[1]) == '0) begin
        if(tif.ts == ts_w_lsex)
          tif.ts = ts_rdy;
        if(tif.ts == ts_lsex_w_if)
          tif.ts = ts_w_if;        
      end
      tin[io.lsu.lid][io.lsu.ltid] = tif;
    end
    
    if(io.exu.req && inf.isu2exu.rsp) begin
      isu_thrd_inf_s tif;
      tif = tin[io.exu.lid][io.exu.ltid];
      if(io.exu.asyn) begin
        isu_oid_t oid;
        oid = '0;
        for(int i = 0; i < NUM_ISU_OCNT; i++)
          if(tif.oid[io.exu.ls][i] == io.lsu.oid && tif.ocnt[io.exu.ls][i])
            oid = i;
        tif.ocnt[oid] = '0;
      end else
        tif.sblock[0] = '0;
      if(!tif.sblock[1] && (tif.ocnt[2] & tif.omsk[2]) == '0) begin
        if(tif.ts == ts_w_lsex)
          tif.ts = ts_rdy;
        if(tif.ts == ts_lsex_w_if)
          tif.ts = ts_w_if;        
      end
      tin[io.exu.lid][io.exu.ltid] = tif;
    end
    
    ///execute COP inst in isu
    begin
      lid_t l;
      l = li[1].en && !li[1].vec;
      
      if(li[l].en && !li[l].vec && li[l].opcode[8:5] == 4'b0101) begin
        case(li[l].opcode)
          op_cop6 : ///asyn mem bar
          begin
            isu_thrd_inf_s tif;
            tif = tin[l][li[l].ltid];
            if(li[l].imm[4])
              tif.omsk[0] = li[l].imm[3:0];
            if(li[l].imm[9])
              tif.omsk[1] = li[l].imm[8:5];
            if(li[l].imm[14])
              tif.omsk[2] = li[l].imm[13:10];
            if((tif.ocnt[0] & tif.omsk[0]) == '0
            || (tif.ocnt[1] & tif.omsk[1]) == '0
            || (tif.ocnt[2] & tif.omsk[2]) == '0) begin
              if(tif.ts == ts_w_if)
                tif.ts = ts_lsex_w_if;
              if(tif.ts == ts_rdy)
                tif.ts = ts_w_lsex;                
            end
          end
        endcase
      end
    end
    
    begin ///info to function units
      isu_fui3_inf_s fuit;
      logic en;
      
      en = '0;
      fuit = fui2[s.exFu];
      
      for(int f = 0; f < NUM_FU; f++) begin
        inf.isu2dpu.fuOP[f] = fui2[f].opcode;
        inf.isu2dpu.fuReq[f] = fui2[f].en && !(s.vext && s.exFu == f);
        en |= inf.isu2dpu.fuReq[f];
      end
      inf.isu2dpu.last = cycEnd && en;
      inf.isu2dpu.spOP = spi.opcode;
      inf.isu2dpu.spGid = spi.gid;
      inf.isu2dpu.spEn = spi.en;
      
      inf.isu2lsu.req = lsi2.en;
      inf.isu2lsu.last = cycEnd && lsi2.en;
      inf.isu2lsu.wrf = lsi2.wrf;
      inf.isu2lsu.ltid = lsi2.ltid;
      inf.isu2lsu.lid = lsi2.lid;
      inf.isu2lsu.ls = lsi2.opcode[7];
      inf.isu2lsu.fun = lsi2.opcode[3:0];
      inf.isu2lsu.ch = lsi2.opcode[5:4];
      inf.isu2lsu.lg = lsi2.opcode[6];
      inf.isu2lsu.gid = lsi2.gid;
      inf.isu2lsu.oid = lsi2.oid;
      inf.isu2lsu.asyn = lsi2.asyn;
      
      inf.isu2exu.req = fuit.en;
      inf.isu2exu.last = cycEnd && fuit.en;
      inf.isu2exu.wrf = fuit.wrf;
      inf.isu2exu.ltid = fuit.ltid;
      inf.isu2exu.lid = fuit.lid;
      inf.isu2exu.opcode = fuit.opcode;
    end
  end : comb_logic

  always_comb
  begin : iorsp_logic
    ion = io;
        
    if(inf.dpu2isu.req)
      ion.dpu = inf.dpu2isu;
    else
      ion.dpu.req = '0;
      
    for(int l = 0; l < NUM_LANE; l++)
      if(inf.ifu2isu.rsp[l]) begin
        ion.ifu.rsp[l] = '1;
        ion.ifu.ltid[l] = inf.ifu2isu.ltid[l];
        ion.ifu.inst[l] = inf.ifu2isu.inst[l];
        ion.ifu.pc[l] = inf.ifu2isu.pc[l];
      end else
        ion.ifu.rsp[l] = '0;
    
    if(inf.isu2lsu.rsp)
      ion.lsu = inf.lsu2isu;
    ion.lsu.vblock = inf.lsu2isu.vblock;
    
    if(inf.isu2sau.rsp)
      ion.sau = inf.sau2isu;
    ion.sau.sblock = inf.sau2isu.sblock;
 
    if(inf.isu2exu.rsp)
      ion.exu = inf.exu2isu;      
    ion.exu.vblock = inf.exu2isu.vblock;
    ion.exu.sblock = inf.exu2isu.sblock;
  end : iorsp_logic
  
endmodule : xpip_rtl_isu